import datetime
import calendar
import time

__all__ = ['AnyWay']
from ..request import *
class AnyWay(Request):

    security = 0.5 # требуемый уровень безопасности пути (включительно), меньше просто не рассматривать
    cargo = 3000 # объём места в грузовом отсеке (с учётом компрессий и контейнеров)
    money = 500000000 # сколько у нас есть денег в пределе
    tax = 0.01 # прикидка на сдирание денег налогами (по факту продажи)
    fee = 0.01 # ... брокерами (при постановке на продажу)
    now = datetime.datetime.utcnow() # базовое время, которое мы считаем за "сейчас" (для подмены в аргументах потом)
    age = datetime.timedelta(5) # за какой период времени рассматривать экспорты (более старые отсеиваем), в днях
    way = datetime.timedelta(3/24) # какое время истчениея у заказа должно быть, чтоб успеть подумать и долететь (запас от now)
    sort_field = "profit_per_jump" # сортировка, одно из набора полей в выборке
    sort_order = "desc" # сортировка, порядок
    min_profit_per_trip = 100000 # минимальный профит
    min_profit_per_jump = 100000 # ...

    def __init__(self, db, **params):
        super().__init__(db)
        self.params = params

    def __iter__(self):
        actual_params = {}
        for name in self.params: actual_params[name] = self.params[name]
#        for name in      params: actual_params[name] =      params[name]

        actual_params['security'] = int(round(actual_params['security'] * 10) * 10)
        sort_field = actual_params['sort_field']
        sort_order = actual_params['sort_order']
        del actual_params['sort_field']
        del actual_params['sort_order']


        s = datetime.datetime.now()# make benchmarks as a separate static class for the whole project

        #!!! MOVE query to class var
        query = """
        SELECT
            sub.*,
            sr.name as source_region_name,
            br.name as target_region_name,
            ss.name as source_system_name,
            bs.name as target_system_name,
            st.name as source_station_name,
            bt.name as target_station_name
        FROM (
        SELECT
            s.order_id              as source_order_id,
            s.region_id             as source_region_id,
            s.system_id             as source_system_id,
            s.station_id            as source_station_id,
            s.price                 as source_price,

            b.order_id              as target_order_id,
            b.region_id             as target_region_id,
            b.system_id             as target_system_id,
            b.station_id            as target_station_id,
            b.price                 as target_price,

            t.length                as length,
            t.security::float / 100 as security,
            i.name                  as item_name,

            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) as amount,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * i.volume as volume,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * s.price as money,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * b.price * %(tax)s as tax,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * b.price * %(fee)s as fee,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * (b.price - s.price) as income_per_trip,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * (b.price - s.price) / greatest(1, t.length) as income_per_jump,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * (b.price - s.price - s.price * %(tax)s - s.price * %(fee)s) as profit_per_trip,
            least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) * (b.price - s.price - s.price * %(tax)s - s.price * %(fee)s) / greatest(1, t.length) as profit_per_jump,
            %(now)s::integer - least(b.exported, s.exported) as age

        FROM "items"    i
        JOIN "sellers"  s   ON( s."item_id" = i."item_id" AND s."displaced" > %(now)s
                                    AND s.exported > %(now)s::integer - %(age)s::integer
                                    AND s.expires  > %(now)s::integer + %(way)s::integer
                                    AND %(cargo)s::bigint > i.volume * s.minimal
                                    AND %(money)s::bigint > s.price  * s.minimal
                                    )
        JOIN "buyers"   b   ON( b."item_id" = s."item_id" AND b."displaced" > %(now)s and b.price > s.price
                                    AND b.exported > %(now)s::integer - %(age)s::integer
                                    AND b.expires  > %(now)s::integer + %(way)s::integer
                                    AND %(cargo)s::bigint > i.volume * b.minimal
                                    AND %(money)s::bigint > s.price  * b.minimal
                                        AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * s.remains > %(min_profit_per_trip)s::float
                                        AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * b.remains > %(min_profit_per_trip)s::float
                                AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * %(cargo)s > %(min_profit_per_trip)s::float * i.volume
                                AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * %(money)s > %(min_profit_per_trip)s::float * s.price
                            )
        JOIN "trips"    t   ON( t.security >= %(security)s::smallint
                            AND t.source_system_id = s.system_id
                            AND t.target_system_id = b.system_id
                                AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * s.remains > %(min_profit_per_jump)s::float * t.length
                                AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * b.remains > %(min_profit_per_jump)s::float * t.length
                                AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * %(cargo)s > %(min_profit_per_jump)s::float * t.length * i.volume
                                AND (b.price - s.price * (1.0 + %(tax)s::float + %(fee)s)::float) * %(money)s > %(min_profit_per_jump)s::float * t.length * s.price
                            )
        WHERE true
          AND s.remains > b.minimal
          AND b.remains > s.minimal
        ORDER BY \"""" + sort_field + """\" """ + sort_order + """
        LIMIT 100

        ) sub
        LEFT JOIN "regions"    sr ON (sr.region_id = sub.source_region_id)
        LEFT JOIN "regions"    br ON (br.region_id = sub.target_region_id)
        LEFT JOIN "systems"    ss ON (ss.system_id = sub.source_system_id)
        LEFT JOIN "systems"    bs ON (bs.system_id = sub.target_system_id)
        LEFT JOIN "stations"   st ON (st.station_id = sub.source_station_id)
        LEFT JOIN "stations"   bt ON (bt.station_id = sub.target_station_id)
        """

        """
#!!! Добавить тест и булево поле на адекватность (remains >= minimal), и по нему тоже фильтровать. но и таких надо сохранять для истории.
#!!! с другой стороны, индекс по remains/minimal уже должен быть для s->b, b->s, так что не убудет и на месте проверить.

/* WAS: Ксатти!!! Эта формула не учитывает скупку товара от двух продавцов в одном или близких местах, и вывоз суммарный. и уж тем более мульти-товарный карго.
          AND least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) > b.minimal
          AND least(s.remains, b.remains, floor(%(cargo)s / i.volume), floor(%(money)s / s.price)) > s.minimal
*/
        """

#        print(query % param)
        #??? Maybe make some post-processing and typecasting of retrieved values. and make yielding here to emulate original cursor's iterator.
        return self.query(query, actual_params)
